package com.ruoyi.miniapp.controller;

import java.io.BufferedReader;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.WeChatUtil;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.miniapp.ali.ChinesePinyinUtil;
import com.ruoyi.miniapp.config.WeChatMiniappProperty;
import com.ruoyi.miniapp.domain.*;
import com.ruoyi.miniapp.dto.CreateAdmOrderDto;
import com.ruoyi.miniapp.mapper.ContractTemplateMapper;
import com.ruoyi.miniapp.mongo.WxUserHandler;
import com.ruoyi.miniapp.service.*;
import com.tdd.wx.users.entity.WxUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;

/**
 * 加盟商购买点位订单Controller
 *
 * @author lobyliang
 * @date 2022-01-14
 */
@RestController
@RequestMapping("fraSeatAgreement")
@Api(tags = "加盟商购买点位订单")
public class FranSeatAgreementController extends BaseController {
    @Autowired
    private IFranSeatAgreementService franSeatAgreementService;
    @Autowired
    private IBasVdmModelService basVdmModelService;
    @Autowired
    private IAdmSeatsService admSeatsService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private WxUserHandler wxUserHandler;
    @Autowired
    private IFranSeatAgreementItemService franSeatAgreementItemService;
    @Autowired
    private IAdmProcPlanService admProcPlanService;
    @Autowired
    private IAdmProcPlanItemService admProcPlanItemService;
    @Autowired
    private WeChatMiniappProperty weChatMiniappProperty;
    @Autowired
    private IBasBuildingsService buildingsService;
    @Autowired
    private IBasVillageService basVillageService;

    @Autowired
    private IContractTemplateService contractTemplateService;

    /**
     * 查询加盟商购买点位订单列表
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:list")
    @GetMapping("/list")
    public TableDataInfo list(FranSeatAgreement franSeatAgreement) {
        startPage();
        List<FranSeatAgreement> list = franSeatAgreementService.selectFranSeatAgreementList(franSeatAgreement);
        return getDataTable(list);
    }

    /**
     * 导出加盟商购买点位订单列表
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:export")
    @Log(title = "加盟商购买点位订单" , businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, FranSeatAgreement franSeatAgreement) throws IOException {
        List<FranSeatAgreement> list = franSeatAgreementService.selectFranSeatAgreementList(franSeatAgreement);
        ExcelUtil<FranSeatAgreement> util = new ExcelUtil<FranSeatAgreement>(FranSeatAgreement.class);
        util.exportExcel(response, list, "加盟商购买点位订单数据");
    }

    /**
     * 获取加盟商购买点位订单详细信息
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:query")
    @GetMapping(value = "/{pkSeatCode}")
    public AjaxResult getInfo(@PathVariable("pkSeatCode") String pkSeatCode) {
        return AjaxResult.success(franSeatAgreementService.selectFranSeatAgreementByPkSeatCode(pkSeatCode));
    }

    /**
     * 新增加盟商购买点位订单
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:add")
    @Log(title = "加盟商购买点位订单" , businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody FranSeatAgreement franSeatAgreement) {
        return toAjax(franSeatAgreementService.insertFranSeatAgreement(franSeatAgreement));
    }

    /**
     * 修改加盟商购买点位订单
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:edit")
    @Log(title = "加盟商购买点位订单" , businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody FranSeatAgreement franSeatAgreement) {
        return toAjax(franSeatAgreementService.updateFranSeatAgreement(franSeatAgreement));
    }

    /**
     * 删除加盟商购买点位订单
     */
    @RequiresPermissions("miniapp:fraSeatAgreement:remove")
    @Log(title = "加盟商购买点位订单" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{pkSeatCodes}")
    public AjaxResult remove(@PathVariable String[] pkSeatCodes) {
        return toAjax(franSeatAgreementService.deleteFranSeatAgreementByPkSeatCodes(pkSeatCodes));
    }

    @ApiOperation("生成订单")
    @PostMapping("createOrder")
    public R createOrder(@RequestBody CreateAdmOrderDto dto) {
        String unionId = SecurityUtils.getUnionId();
        WxUser wxUser = wxUserHandler.newFindByUnionId(unionId);
        String inviteCode = dto.getInviteCode();
        if(StrUtil.isNotEmpty(inviteCode)){
            while (inviteCode.startsWith("0")){
                inviteCode = inviteCode.substring(1,inviteCode.length());
            }
        }

        if (dto.getAdmSeatsCodes().size() == 0) {
            return R.fail("请先选择点位！");
        }
        if (dto.getAdmModelId() == null) {
            return R.fail("请先选择机器型号！");
        }
        BasVdmModel vdmModel = basVdmModelService.getById(dto.getAdmModelId());
        if (vdmModel == null) {
            return R.fail("未找到该型号！");
        }

        List<String> occupy = franSeatAgreementService.findOccupyAdmSeatCodes();
        for (String s : dto.getAdmSeatsCodes()) {
            if (occupy.contains(s)) {
                redisService.deleteObject("check_adm_seats_" + unionId);
                return R.fail("点位不可用，请重新选择点位！");
            }
        }
        List<AdmSeats> admSeats = admSeatsService.findByCodes(dto.getAdmSeatsCodes());
        //广告机数量
        // 购买点位的数量
        dto.getAdmSeatsCodes().size();
        BigDecimal allPrice = vdmModel.getAdmPrice().multiply(new BigDecimal(dto.getAdmSeatsCodes().size()));
        //创建订单
        redisService.deleteObject("check_adm_seats_" + unionId);
        FranSeatAgreement franSeatAgreement = new FranSeatAgreement();
        if(StrUtil.isNotEmpty(inviteCode)){
            franSeatAgreement.setInviterUserId(HexUtil.hexToLong(inviteCode));
        }
        franSeatAgreement.setPkSeatCode(IdUtil.simpleUUID());
        franSeatAgreement.setPlacementAmount((long) dto.getAdmSeatsCodes().size());
        franSeatAgreement.setIsPayment(0L);
        franSeatAgreement.setCreateDate(DateTime.now());
        franSeatAgreement.setTotalPrice(allPrice);
        franSeatAgreement.setHasCancel(0);
        franSeatAgreement.setFranchiseesId(wxUser.getSysUserId());
        franSeatAgreement.setFranchiseesUnionid(unionId);
        franSeatAgreement.setAdmSeatsCodes(String.join("," , dto.getAdmSeatsCodes()));
        franSeatAgreement.setOutTradeNo(DateTime.now().toString("yyyyMMddHHmmsss")+ RandomUtil.randomNumbers(4));
        franSeatAgreement.setOrderNo(DateTime.now().toString("yyyyMMddHHmmsss") + RandomUtil.randomNumbers(4));
        franSeatAgreementService.save(franSeatAgreement);
        //创建子订单
        for (AdmSeats as : admSeats) {
            FranSeatAgreementItem item = new FranSeatAgreementItem();
            item.setFkSeatCode(franSeatAgreement.getPkSeatCode());
            item.setPlacementInfo(JSONUtil.toJsonStr(as));
            /**
             * 补全 广告机单价 PlacementPrice 到 FranSeatAgreementItem 表中
             * 修改时间:2022-03-22 songping
             */
            item.setPlacementPrice(vdmModel.getAdmPrice());
            /**
             * 补全 投资人分润金额 FranPricePerBag 到 FranSeatAgreementItem 表中
             * 修改时间:2022-03-22 songping
             */
            ContractTemplate conTemplate = contractTemplateService.getConTemplate(CON_TYPE);
            ConContent content = JSONUtil.toBean(conTemplate.getContent(),ConContent.class);
            logger.info("合同模板明细数据为..." + content);
            item.setFranPricePerBag(content.getFranPricePerBag());
            //item.setPlacementPrice(as.getFranPricePerBag()); //todo 错了，应该是机器型号中的单价
            //item.setFranPricePerBag(合同表中的投资人 单价/每袋子);//todo 应该从合同表读单价，不要更新到机位表，在付款完成后再更新机位表
            item.setPlacementCode(as.getPkSeatCode());
            item.setItemOrderNo(franSeatAgreement.getOrderNo() + RandomUtil.randomNumbers(2));
            item.setBuildingsCode(as.getFkBuildingCode());
            item.setVillageCode(as.getFkVillageCode());
            item.setVdmModelId(dto.getAdmModelId());
            BasVillage basVillage = basVillageService.getByCode(as.getFkVillageCode());
            if(basVillage != null){
                item.setVillageName(basVillage.getVillageName());
            }
            BasBuildings buildings = buildingsService.getById(as.getFkBuildingCode());
            if(buildings != null){
                item.setBuildingsName(buildings.getBuildingNo()+"栋");
            }
            franSeatAgreementItemService.save(item);
        }
        return R.ok(franSeatAgreement);
    }

    @ApiOperation("我的订单列表")
    @GetMapping("myList")
    public R myList(Page<FranSeatAgreement> page,Integer payState) {
        String unionid = SecurityUtils.getUnionId();
        franSeatAgreementService.listPage(page, unionid,payState);
        return R.ok(page);
    }

    @ApiOperation("单体查询")
    @GetMapping("getById")
    public R getById(String pkSeatCode) {
        FranSeatAgreement franSeatAgreement = franSeatAgreementService.getById(pkSeatCode);
        franSeatAgreement.setItemList(franSeatAgreementItemService.findBySeatCode(pkSeatCode));
        return R.ok(franSeatAgreement);
    }


    @ApiOperation("生成预支付订单")
    @GetMapping("toPay")
    public R toPay(String pkSeatCode){
        String unionid = SecurityUtils.getUnionId();
        WxUser wxUser = wxUserHandler.findByUnionId(unionid);
        FranSeatAgreement franSeatAgreement = franSeatAgreementService.getById(pkSeatCode);
        if(StrUtil.isEmpty(franSeatAgreement.getOutTradeNo())){
            String outTradeNo = DateTime.now().toString("yyyyMMddHHmmsss")+ RandomUtil.randomNumbers(4);
            franSeatAgreement.setOutTradeNo(outTradeNo);
            franSeatAgreementService.updateOutTradeNo(franSeatAgreement.getPkSeatCode(),outTradeNo);
        }
        //生成预支付订单
        try {
            BigDecimal totalPrice = franSeatAgreement.getTotalPrice().multiply(new BigDecimal(100));
            Map prePayRes = WeChatUtil.payUnifiedorder(weChatMiniappProperty.getAppid(),"淘袋袋-广告机",franSeatAgreement.getOutTradeNo(),totalPrice.longValue(),wxUser.getOpenId());
            if(prePayRes == null){
                return R.fail();
            }
            Map<String,Object> signParam = new HashMap<>();
            signParam.put("appId",weChatMiniappProperty.getAppid());
            signParam.put("nonceStr", MapUtil.getStr(prePayRes,"nonce_str"));
            signParam.put("package","prepay_id="+MapUtil.getStr(prePayRes,"prepay_id"));
            signParam.put("timeStamp",DateTime.now().getTime()+"");
            signParam.put("signType","MD5");
            String paySign = WeChatUtil.getSign(signParam);
            signParam.put("paySign",paySign);
            return R.ok(signParam);
        }catch (Exception e){
            logger.error("生成预支付订单失败==》"+e.getMessage());
            return R.fail();
        }
    }

    /**
     * @deprecated 实际线上未被使用 仅用于本地测试使用 标注时间:2022-03-21  songping
     * @param pkSeatCode
     * @return
     */
    @ApiOperation("支付完成")
    @GetMapping("paySuccess")
    public R paySuccess(String pkSeatCode) {
        FranSeatAgreement franSeatAgreement = franSeatAgreementService.getById(pkSeatCode);
        franSeatAgreement.setIsPayment(1L);
        franSeatAgreement.setPayTime(DateTime.now());
        franSeatAgreementService.updateById(franSeatAgreement);
        //生成生产计划
        AdmProcPlan admProcPlan = admProcPlanService.findBySeatOrderCode(franSeatAgreement.getPkSeatCode());
        if(admProcPlan == null){
            admProcPlan = new AdmProcPlan();
            admProcPlan.setDtProcStatusNo("0");
            admProcPlan.setCreateDate(DateTime.now());
            admProcPlan.setFkSeatOrderCode(franSeatAgreement.getPkSeatCode());
            admProcPlan.setPlanAmount(franSeatAgreement.getPlacementAmount().toString());
            admProcPlanService.save(admProcPlan);
            List<FranSeatAgreementItem> franSeatAgreementItemList = franSeatAgreementItemService.findBySeatCode(franSeatAgreement.getPkSeatCode());
            for (FranSeatAgreementItem item : franSeatAgreementItemList) {
                AdmSeats as = JSONUtil.toBean(item.getPlacementInfo(), AdmSeats.class);
                AdmProcPlanItem r = new AdmProcPlanItem();
                BasVdmModel basVdmModel = basVdmModelService.getById(item.getVdmModelId());
                r.setFkAdmPlanCode(admProcPlan.getPkAdmProcCode());
                r.setFkVillageCode(as.getFkVillageCode());
                r.setFkVdmModelId(item.getVdmModelId().toString());
                r.setFkFranchiseeId(franSeatAgreement.getFranchiseesId() == null ? null : franSeatAgreement.getFranchiseesId());
                r.setProductName(basVdmModel.getVdmModelName());
                r.setProcCreateDate(DateTime.now());
                admProcPlanItemService.save(r);
            }
        }
        return R.ok();
    }

    /**
     * 顺序码初始值
     * 2022-03-24 songping
     */
    private static final String SEQUENCE_CODE = "001";
    /**
     * 合同模板类型
     * 2022-03-24 songping
     */
    private static final Integer CON_TYPE = 502;

    @PostMapping("/open/wxPayNotify")
    public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception{
        logger.info("进入支付回调！");
        BufferedReader reader = null;
        String xmlStr = null;
        reader = request.getReader();
        String line = null;
        StringBuffer sb = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        xmlStr = sb.toString();
        Map map = XmlUtil.xmlToMap(xmlStr);
        String outTradeNo = MapUtil.getStr(map,"out_trade_no",null);
        logger.info("支付回调====》"+outTradeNo);
        FranSeatAgreement franSeatAgreement = franSeatAgreementService.findByOutTradeNo(outTradeNo);
        if(franSeatAgreement != null){
            franSeatAgreementService.updatePayStatus(franSeatAgreement.getPkSeatCode());
            //生成生产计划
            AdmProcPlan admProcPlan = admProcPlanService.findBySeatOrderCode(franSeatAgreement.getPkSeatCode());
            if(admProcPlan == null){
                admProcPlan = new AdmProcPlan();
                admProcPlan.setDtProcStatusNo("0");
                admProcPlan.setCreateDate(DateTime.now());
                admProcPlan.setFkSeatOrderCode(franSeatAgreement.getPkSeatCode());
                admProcPlan.setPlanAmount(franSeatAgreement.getPlacementAmount().toString());
                admProcPlanService.save(admProcPlan);
                List<FranSeatAgreementItem> franSeatAgreementItemList = franSeatAgreementItemService.findBySeatCode(franSeatAgreement.getPkSeatCode());
                for (FranSeatAgreementItem item : franSeatAgreementItemList) {
                    AdmSeats as = JSONUtil.toBean(item.getPlacementInfo(), AdmSeats.class);
                    /**
                     * 更新 PlacementInfo 字段的数据 到 fran_seat_agreement_item 表中
                     * 修改时间:2022-03-22 songping
                     */
                    as.setFranPricePerBag(item.getFranPricePerBag());
                    as.setFkFranchiseeId(franSeatAgreement.getFranchiseesId()+"");
                    item.setPlacementInfo(JSONUtil.toJsonStr(as));
                    franSeatAgreementItemService.updPlacementInfoByFranSeatItemId(item.getPkFranSeatItemId(),item.getPlacementInfo());

                    AdmProcPlanItem r = new AdmProcPlanItem();
                    BasVdmModel basVdmModel = basVdmModelService.getById(item.getVdmModelId());
                    r.setFkAdmPlanCode(admProcPlan.getPkAdmProcCode());
                    r.setFkVillageCode(as.getFkVillageCode());
                    r.setFkVdmModelId(item.getVdmModelId().toString());
                    r.setFkFranchiseeId(franSeatAgreement.getFranchiseesId() == null ? null : franSeatAgreement.getFranchiseesId());
                    r.setProductName(basVdmModel.getVdmModelName());
                    r.setProcCreateDate(DateTime.now());
                    /**
                     *   处理 AdmProcPlanItem 生产计划表 主键 自定义生成
                     *   修改时间:2022-03-21 songping
                     */
                    String namePath = contractTemplateService.getNamePathByVillageCode(item.getVillageCode());
                    String sequenceCode = contractTemplateService.getMaxSequenceCodeByVillageCode(item.getVillageCode());
                    /**
                     *  生成的生产计划的code
                     */
                    String productionCode;
                    if(ObjectUtils.isEmpty(sequenceCode)){
                        productionCode = ChinesePinyinUtil.getPinYinHeadChar(namePath).trim() + SEQUENCE_CODE;
                    }else{
                        productionCode = ChinesePinyinUtil.getPinYinHeadChar(namePath).trim() + ChinesePinyinUtil.createNewBidNumber(sequenceCode);
                    }
                    r.setProductSerialCode(productionCode);
                    /**
                     *   根据 机位的id 查询 当前机位是否有机器
                     *   修改时间:2022-03-21 songping
                     */
                    AdmSeats seats = admSeatsService.selectAdmSeatsByPkSeatCode(item.getPlacementCode());
                    /**
                     *  如果当前机位没有机器 即 ActivationDate 为空 那么 admProcPlanItem 中 is_production 字段为 1 表示需要生产
                     *  修改时间:2022-03-21 songping
                     */
                    if(ObjectUtils.isEmpty(seats.getActivationDate())){
                        r.setIsProduction(1);
                    }
                    admProcPlanItemService.save(r);
                    admSeatsService.updateSeatEmpt(as.getPkSeatCode(),0);
                    admSeatsService.updateFranchiseeIdByCodes(item.getPlacementCode(),franSeatAgreement.getFranchiseesId());
                    /**
                     * todo 这里，要把FranSeatAgreementItem 里面的单价/每袋子 更新到机位信息中
                     */
                    /**
                     *
                     * 补全 投资人分润金额 FranPricePerBag 到 adm_seats 表中 修改时间:2022-03-22 songping
                     * 修改时间:2022-03-21 songping
                     */
                    admSeatsService.updateFranPricePerBagByCode(item.getPlacementCode(),item.getFranPricePerBag());
                }
            }
            return;
        }else {
            response.setStatus(500);
            //获取输出流
            PrintWriter out = response.getWriter();
            Map rtMap = new HashMap();
            rtMap.put("code","FAIL");
            rtMap.put("message","失败");
            out.println(JSONUtil.toJsonStr(rtMap));
        }
    }

}
